package linkExcel;

import cn.hutool.core.util.StrUtil;
import linkExcel.utils.ExcelUtils;
import linkExcel.utils.ToolUtils;
import linkExcel.vo.ExcelVo;
import org.apache.poi.common.usermodel.HyperlinkType;
import org.apache.poi.ss.usermodel.*;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.Collator;
import java.util.*;

/**
 * 针对目标文件夹下所有文件的每一个一级文件夹保存至一个sheet
 */
public class MultipleMain {

    private static final String EXCEL_PATH = "E:\\引绰济辽\\1.部门工作\\图纸台账\\施工蓝图2023.11.06\\__台账\\图纸台账_枢纽二标.xlsx";
    private static final String BEGIN_PATH = "E:\\引绰济辽\\1.部门工作\\图纸台账\\施工蓝图2023.11.06\\1文得根水利枢纽\\3枢纽二标";

    private static List<String> ERROR_ITEMS = new ArrayList<>();

    private static Integer PDF_NUMS = 0;

    private static Integer NO_CODE_NUM = 0;

    public static void main(String[] args) {
        //创建或选择Excel
        Workbook workbook = ExcelUtils.createOrGetExcel(EXCEL_PATH, null);
        //遍历所有文件
        File file = new File(BEGIN_PATH);
        LinkedHashMap<String, List<ExcelVo>> vosMap = traverseFolderFather(file);
        vosMap.forEach((sheetName, vos) -> {
            //记录图纸数量
            PDF_NUMS += vos.size();
            //创建或选择sheet
            Sheet sheet = ExcelUtils.createOrGetSheet(workbook, sheetName);
            //创建表头
            initTableHeader(sheet);
            // 填充数据
            for (int i = 0; i < vos.size(); i++) {
                ExcelVo vo = vos.get(i);
                Row dataRow = sheet.createRow(i + 1);
                //数据
                dataRow.createCell(0).setCellValue(i + 1);
                dataRow.createCell(1).setCellValue(vo.getName());
                dataRow.createCell(2).setCellValue(vo.getCode());
                dataRow.createCell(3).setCellValue("");
                dataRow.createCell(4).setCellValue("");
                dataRow.createCell(5).setCellValue("");
                //判断图号是否为空
                if (StrUtil.isBlank(vo.getCode())) {
                    dataRow.createCell(4).setCellValue("图纸无图号");
                    NO_CODE_NUM++;
                }
                // 创建超链接
                CreationHelper creationHelper = workbook.getCreationHelper();
                Hyperlink hyperlink = creationHelper.createHyperlink(HyperlinkType.FILE);
                try {
                    // 为超链接单元格添加超链接
                    hyperlink.setAddress(vo.getRelativeLink());
                    dataRow.getCell(1).setHyperlink(hyperlink);
                    //样式
                    CellStyle cellStyle = dataRow.getCell(1).getCellStyle();
                    CellStyle newStyle = workbook.createCellStyle();
                    newStyle.cloneStyleFrom(cellStyle);
                    Font font = workbook.createFont();
                    font.setColor(IndexedColors.BLUE.getIndex());
                    newStyle.setFont(font);
                    dataRow.getCell(1).setCellStyle(newStyle);
                } catch (Exception e) {
                    dataRow.createCell(5).setCellValue("超链加注失败，原因为：" + e.getCause());
                    ERROR_ITEMS.add("工作簿【" + sheetName + "】-第[" + (i + 1) + "]行-出现错误：" + e.getCause());
                    //样式
                    CellStyle cellStyle = dataRow.getCell(5).getCellStyle();
                    CellStyle newStyle = workbook.createCellStyle();
                    newStyle.cloneStyleFrom(cellStyle);
                    Font font = workbook.createFont();
                    font.setColor(IndexedColors.RED.getIndex());
                    newStyle.setFont(font);
                    dataRow.getCell(5).setCellStyle(newStyle);
                }
            }
            // 遍历已填充的单元格
            for (int rowIdx = 0; rowIdx <= vos.size(); rowIdx++) {
                Row dataRow = sheet.getRow(rowIdx); // 获取行
                for (int colIdx = 0; colIdx <= 5; colIdx++) {
                    Cell cell = dataRow.getCell(colIdx); // 获取单元格
                    // 创建一个新样式并设置黑色边框
                    if (cell != null) {
                        CellStyle cellStyle = workbook.createCellStyle();
                        cellStyle.cloneStyleFrom(cell.getCellStyle());
                        cellStyle.setBorderTop(BorderStyle.THIN);
                        cellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
                        cellStyle.setBorderBottom(BorderStyle.THIN);
                        cellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
                        cellStyle.setBorderLeft(BorderStyle.THIN);
                        cellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
                        cellStyle.setBorderRight(BorderStyle.THIN);
                        cellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
                        cell.setCellStyle(cellStyle);
                    }
                }
            }
        });
        //删除创建excel时的第一个sheet
        workbook.removeSheetAt(workbook.getSheetIndex("sheet"));
        //打印错误结果
        System.out.println("图纸台账录入完成，图号为空数量共计："+NO_CODE_NUM+"条");
        System.out.println("共计[" + (PDF_NUMS - ERROR_ITEMS.size()) + "/" + PDF_NUMS + "]条。" + (ERROR_ITEMS.isEmpty() ? "超链加注全部成功" : "部分超链加注失败，失败内容如下"));
        if (!ERROR_ITEMS.isEmpty()) {
            ERROR_ITEMS.forEach(System.out::println);
        }
        //存入Excel保存
        ExcelUtils.saveExcel(workbook, EXCEL_PATH);
    }

    /**
     * 初始化表头（以及列宽）
     *
     * @param sheet 工作簿
     */
    private static void initTableHeader(Sheet sheet) {
        // 创建表头行
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("序号");
        headerRow.createCell(1).setCellValue("名称");
        headerRow.createCell(2).setCellValue("图号");
        headerRow.createCell(3).setCellValue("签名备注");
        headerRow.createCell(4).setCellValue("图号备注");
        headerRow.createCell(5).setCellValue("其它备注");

        // 设置列宽度（以字符数为单位）
        sheet.setColumnWidth(0, 8 * 256);
        sheet.setColumnWidth(1, 60 * 256);
        sheet.setColumnWidth(2, 25 * 256);
        sheet.setColumnWidth(3, 15 * 256);
        sheet.setColumnWidth(4, 15 * 256);
        sheet.setColumnWidth(5, 15 * 256);
    }

    /**
     * 遍历1级文件夹（需创建sheet的文件夹）
     * @param folder 0级文件夹(总文件夹)
     * @return 排序后的0级文件夹(总文件夹)
     */
    private static LinkedHashMap<String, List<ExcelVo>> traverseFolderFather(File folder) {
        LinkedHashMap<String, List<ExcelVo>> map = new LinkedHashMap<>();
        if (folder.isDirectory()) {
            // 获取文件夹内的文件和子文件夹
            File[] subFiles = folder.listFiles();
            if (subFiles != null) {
                sortFiles(subFiles);
                //if记录一级目录下面的文件，else+if记录同一级目录的零散文件
                List<ExcelVo> otherFiles = new ArrayList<>();
                for (File file : subFiles) {
                    if (file.isDirectory()) {
                        String sheetName = file.getName();
                        System.out.println("\uD83D\uDD37检索到工作簿级别文件夹：【" + file.getName() + "】");
                        // 递归遍历子文件夹
                        List<ExcelVo> vos = new ArrayList<>(traverseFolderSon(file));
                        map.put(sheetName, vos);
                    } else {
                        if (file.getName().endsWith(".pdf")) {
                            otherFiles.add(new ExcelVo() {{
                                setName(file.getName());
                                setCode(ToolUtils.extractGraphNumber(file.getName()));
                                setRelativeLink(ToolUtils.getRelativePath(file.getPath(), EXCEL_PATH));
                            }});
                        }
                    }
                }
                if (!otherFiles.isEmpty()) {
                    map.put("其他图纸类别", otherFiles);
                }
            }
        }
        return map;
    }

    /**
     * 按Windows顺序进行排序
     * @param subFiles 文件夹列表
     */
    private static void sortFiles(File[] subFiles) {
        //从文件列表获取文件名称列表
        LinkedList<String> list = new LinkedList<>();
        for (File file : subFiles) {
            list.add(file.getName());
        }
        //对文件名称排序：这是比较方法（可比较中文，但对于生僻字，效果不太好）
        Comparator<Object> CHINA_COMPARE = Collator.getInstance(java.util.Locale.CHINA);
        list.sort((o1, o2) -> {
            //比较的基本原则，拿最小长度的字符串进行比较，若全部相等，则长字符串往后排
            int len1 = o1.length();
            int len2 = o2.length();
            int len = (len1 - len2) <= 0 ? len1 : len2;
            StringBuilder sb1 = new StringBuilder();
            StringBuilder sb2 = new StringBuilder();
            for (int i = 0; i < len; i++) {
                String s1 = o1.substring(i, i + 1);
                String s2 = o2.substring(i, i + 1);
                if (isNumeric(s1) && isNumeric(s2)){
                    //取出所有的数字
                    sb1.append(s1);
                    sb2.append(s2);
                    //取数字时，不比较
                    continue;
                }
                if (sb1.length() != 0 && sb2.length() != 0){
                    if (!isNumeric(s1) && !isNumeric(s2)){
                        int value1 = Integer.valueOf(sb1.toString());
                        int value2 = Integer.valueOf(sb2.toString());
                        return value1 - value2;
                    } else if (isNumeric(s1)) {
                        return 1;
                    } else if (isNumeric(s2)) {
                        return -1;
                    }
                }
                int result = CHINA_COMPARE.compare(s1, s2);
                if (result != 0) {
                    return result;
                }
            }
            //这一步：是为了防止以下情况：第10  第20，正好以数字结尾，且字符串长度相等
            if (len1 == len2 && sb1.length() != 0 && sb2.length() != 0) {
                int value1 = Integer.valueOf(sb1.toString());
                int value2 = Integer.valueOf(sb2.toString());
                return value1 - value2;
            }
            //若前面都相等，则直接比较字符串的长度，长的排后面，短的排前面
            return Integer.compare(len1, len2);
        });
        // 创建自定义比较器，根据排序好的名称对文件列表进行排序
        Arrays.sort(subFiles, new Comparator<File>() {
            @Override
            public int compare(File file1, File file2) {
                String name1 = file1.getName();
                String name2 = file2.getName();

                int index1 = list.indexOf(name1);
                int index2 = list.indexOf(name2);

                // 如果两个文件名都在 sortList 中，根据 sortList 顺序排序
                if (index1 >= 0 && index2 >= 0) {
                    return Integer.compare(index1, index2);
                }
                // 如果只有一个文件名在 sortList 中，将它排在前面
                else if (index1 >= 0) {
                    return -1;
                } else if (index2 >= 0) {
                    return 1;
                }
                // 如果都不在 sortList 中，按文件名自然顺序排序
                return name1.compareTo(name2);
            }
        });
    }

    /**
     * 判断是否是数字
     * @param s 字符串
     * @return 是否是数字
     */
    private static boolean isNumeric(String s){
        return Character.isDigit(s.charAt(0));
    }


    /**
     * 遍历文件夹下的所有文件
     *
     * @param folder 文件（夹）
     * @return 文件vo对象集合
     */
    private static List<ExcelVo> traverseFolderSon(File folder) {
        List<ExcelVo> vos = new ArrayList<>();
        if (folder.isDirectory()) {
            System.out.println("\uD83D\uDFE0文件夹：【" + folder.getName() + "】");
            // 获取文件夹内的文件和子文件夹
            File[] subFiles = folder.listFiles();
            if (subFiles != null) {
                for (File file : subFiles) {
                    // 递归遍历子文件夹
                    vos.addAll(traverseFolderSon(file));
                }
            }
        } else {
            if (folder.getName().endsWith(".pdf")) {
                vos.add(new ExcelVo() {{
                    setName(folder.getName());
                    setCode(ToolUtils.extractGraphNumber(folder.getName()));
                    setRelativeLink(ToolUtils.getRelativePath(folder.getPath(), EXCEL_PATH));
                }});
            }
        }
        return vos;
    }
}
